//生成文件
package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	pn := getPageNumber()
	chExe := make(chan bool, 10)
	chDone := make(chan bool, 1)
	fr, _ := mkFile("readme.md", true)
	defer fr.Close()
	for i := 1; i <= pn; i++ {
		path := mkDir(i)
		fr.WriteString(fmt.Sprintf("<details>\n\t<summary>%s</summary>\n\nID | Title | Solved\n:----:|:----:|:----:\n", path))
		pi := getPageInfo(i)
		for j, lenth := 0, len(pi); j < lenth; j++ {
			fn := fmt.Sprintf("%s/%s.go", path, pi[j][1])
			fr.WriteString(fmt.Sprintf("%s | [%s](%s) | No\n", pi[j][1], pi[j][3], fn))
			go func(fileName, Problem string) {
				chExe <- true
				f, err := mkFile(fileName, false)
				if err != nil {
					fmt.Printf("创建%s失败\n", fileName)
					chDone <- false
					return
				}
				defer f.Close()
				f.WriteString(fmt.Sprintf("/*\n%s\n\nAnser:\nTime:\n*/", getProblemInfo(Problem)))
				f.WriteString(`
package main

import (
	"fmt"
	"time"
)

func main() {
	tstart := time.Now()



	tend := time.Now()
	fmt.Println(tend.Sub(tstart))
}`)
				chDone <- true
			}(fn, pi[j][2])

		}
		fr.WriteString("</details>\n\n")
	}
	for {
		<-chDone
		<-chExe
		if len(chExe) == 0 {
			break
		}
	}
}

//rawHTML 返回网页源码
func getRawHTML(url string) string {
	resp, _ := http.Get(url)
	b, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	return string(b)
}

//getPageNumber 返回页码总数
func getPageNumber() int {
	url := "https://projecteuler.net/archives"
	rawHTML := getRawHTML(url)
	expr := `<a href="archives;page=\d+?">(\d+?)</a>`
	r := regexp.MustCompile(expr)
	ctx := r.FindStringSubmatch(rawHTML)
	if len(ctx) > 0 {
		p, _ := strconv.Atoi(ctx[1])
		return p
	}
	return 0
}

//getPageInfo 返回页面信息$1,$2,$3:序号,链接,标题
func getPageInfo(p int) [][]string {
	url := "https://projecteuler.net/archives"
	if p > 1 {
		url = fmt.Sprintf("%s;page=%d", url, p)
	}
	rawHTML := getRawHTML(url)
	expr := `(?m)<td class="id_column">(\d+?)</td><td><a href="(.*?)" title=".*?">(.*?)</a></td>`
	r := regexp.MustCompile(expr)
	return r.FindAllStringSubmatch(rawHTML, -1)
}

//getProblemInfo 返回题目信息
func getProblemInfo(url string) string {
	url = fmt.Sprintf("https://projecteuler.net/%s", url)
	rawHTML := getRawHTML(url)
	expr := `(?s)<div class="problem_content" role="problem">.*?<div id="footer" class="noprint">`
	r := regexp.MustCompile(expr)
	raw := r.FindString(rawHTML)
	raw = strings.Replace(raw, "<td></td>", " ", -1)
	raw = strings.Replace(raw, "</tr>", "\n", -1)
	expr = `<td colspan="\d+?"></td>`
	r = regexp.MustCompile(expr)
	raw = r.ReplaceAllStringFunc(raw, func(s string) string {
		re := regexp.MustCompile(`\d+`)
		n, _ := strconv.Atoi(re.FindString(s))
		return strings.Repeat(" ", n)
	})
	expr = `<.*?>`
	r = regexp.MustCompile(expr)
	return strings.TrimSpace(r.ReplaceAllString(raw, ""))
}

//mkDir 创建文件夹
func mkDir(p int) string {
	path := fmt.Sprintf("Page_%d", p)
	if !PathExist(path) {
		os.Mkdir(path, os.ModePerm)
	}
	return path
}

//mk File创建文件
func mkFile(fileName string, force bool) (*os.File, error) {
	if force || !PathExist(fileName) {
		return os.Create(fileName)
	}
	return nil, errors.New("创建失败")
}

//PathExist 判断文件是否存在
func PathExist(path string) bool {
	_, err := os.Stat(path)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}
